"""This module contains views related to shopping cart."""

from django.http import HttpResponse, HttpResponseNotAllowed
from django.shortcuts import get_object_or_404, redirect, render_to_response
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils import simplejson as json

from shop.models import Product


MSG_PRODUCT_ADDED = 'Added %s to shopping cart.'


def _make_json_response(request, **kwargs):
    """Creates a JSON response that includes the number of items in cart and
    the cart table HTML.

    """
    cart = render_to_string('cart_table.html',
        context_instance=RequestContext(request))

    data = kwargs
    data.update({
        'numCartItems': len(request.cart),
        'replace': {
            'cart': cart
        }
    })
    content = json.dumps(data)
    return HttpResponse(content, mimetype='application/json')


def show(request):
    """Show the shopping cart contents."""
    return render_to_response('cart.html',
                              context_instance=RequestContext(request))


def add(request, product_id):
    """Add the given `Product` to the shopping cart.

    The request method must be POST.  If the POST data includes `next`
    parameter, the user will be redirected there.  Otherwise user is redirected
    to cart contents page.  You can make both normal and AJAX requests to this
    view.

    :param product_id: id of the `Product` to be added to the cart

    """
    if request.method == 'POST':
        product = get_object_or_404(Product, pk=product_id)
        request.cart.add(product)

        notice = MSG_PRODUCT_ADDED % product
        if request.is_ajax():
            return _make_json_response(request, notice=notice)
        else:
            request.flash['notice'] = notice
            try:
                next_page = request.POST['next']
            except KeyError:
                return redirect(show)
            else:
                return redirect(next_page)
    return HttpResponseNotAllowed(['POST'])


def update(request, product_id):
    """Update the quantity of given `Product` in the shopping cart.

    The request method must be POST.  The POST data should include the new
    quantity in the `quantity` parameter.  If the `quantity` parameter is not a
    valid integer or is missing, the request will be ignored.  If the new
    quantity is zero or negative, the given product will removed from the
    shopping cart.  The user will be redirected to cart contents page after the
    request.  You can make both normal and AJAX requests to this view.

    :param product_id: id of the `Product` whose quantity is to be updated

    """
    if request.method == 'POST':
        product = get_object_or_404(Product, pk=product_id)

        try:
            quantity = int(request.POST['quantity'])
        except (ValueError, KeyError):
            # Ignore the request if quantity is not set or it is not valid
            # integer.
            pass
        else:
            request.cart.update(product, quantity)

        if request.is_ajax():
            return _make_json_response(request)
        else:
            return redirect(show)

    return HttpResponseNotAllowed(['POST'])


def remove(request, product_id):
    """Remove the given `Product` from the shopping cart.

    The request method must be POST.  If the product is not found in the cart,
    the request will be ignored.  The user will be redirected to cart contents
    page after the request.  You can make both normal and AJAX requests to this
    view.

    :param product_id: id of the `Product` to be removed

    """
    if request.method == 'POST':
        product = get_object_or_404(Product, pk=product_id)
        try:
            request.cart.remove(product)
        except KeyError:
            # Product was not in the cart. Just ignore the exception.
            pass
        if request.is_ajax():
            return _make_json_response(request)
        else:
            return redirect(show)
    return HttpResponseNotAllowed(['POST'])


def clear(request):
    """Removes all products from the shopping cart.

    The request method must be POST.  The user will be redirected to cart
    contents page after the request.  You can make both normal and AJAX requests
    to this view.

    """
    if request.method == 'POST':
        request.cart.clear()
        if request.is_ajax():
            return _make_json_response(request)
        else:
            return redirect(show)
    return HttpResponseNotAllowed(['POST'])


